package com.ihr360.payroll.controller.salarytask.validator;

import com.ihr360.commons.lang.DateUtils;
import com.ihr360.payroll.entity.task.PayPeriodEntity;
import com.ihr360.payroll.entity.task.PayPeriodTermEntity;
import com.ihr360.shared.validator.SessionValidator;
import com.ihr360.validation.ValidationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

@Component
public class PayPeriodEntityValidator extends SessionValidator<PayPeriodEntity> {

    @Autowired
    private PayPeriodTermValidator payPeriodTermValidator;

    @Override
    public boolean supports(Class<?> clazz) {
        return super.supports(clazz) && PayPeriodEntity.class.equals(clazz);
    }

    @Override
    public void validate(PayPeriodEntity target) {
        super.validate(target);

        ValidationUtils.rejectIfEmpty(target.getPlanId(), null, "该账期尚未关联薪资方案");

        List<PayPeriodTermEntity> terms = target.getTerms();
        ValidationUtils.rejectIfEmpty(terms, null, "至少需要设置一个账期批次");
        int size = terms.size();

        Date startOn = target.getStartOn();
        ValidationUtils.rejectIfEmpty(startOn, null, "必须设置账期薪资周期的开始时间");

        Date endOn = target.getEndOn();
        ValidationUtils.rejectIfEmpty(endOn, null, "必须设置账期薪资周期的结束时间");

        startOn = DateUtils.dateFormatYMD(startOn);
        endOn = DateUtils.dateFormatYMD(endOn);
        if (startOn.compareTo(endOn) >= 0) {
            ValidationUtils.reject(null, "账期薪资周期的开始时间必须小于结束时间");
        }

        //账期薪资起止时间与账期批次的总起止时间必须一致
        Date termTotalStartOn = terms.get(0).getStartOn();
        Date termTotalEndOn = terms.get(size - 1).getEndOn();
        if (!DateUtils.isSameDay(startOn, termTotalStartOn)
                || !DateUtils.isSameDay(endOn, termTotalEndOn)) {
            ValidationUtils.reject(null, "账期薪资周期的起止时间必须与所有账期批次中全部薪资周期的总起止时间一致");
        }

        Date attendanceStartOn = target.getAttendanceStartOn();
        ValidationUtils.rejectIfEmpty(attendanceStartOn, null, "必须设置账期考勤周期的开始时间");

        Date attendanceEndOn = target.getAttendanceEndOn();
        ValidationUtils.rejectIfEmpty(attendanceEndOn, null, "必须设置账期考勤周期的结束时间");

        attendanceStartOn = DateUtils.dateFormatYMD(attendanceStartOn);
        attendanceEndOn = DateUtils.dateFormatYMD(attendanceEndOn);
        if (attendanceStartOn.compareTo(attendanceEndOn) >= 0) {
            ValidationUtils.reject(null, "账期考勤周期的开始时间必须小于结束时间");
        }

        //账期考勤起止时间与账期批次的总起止时间必须一致
        Date termTotalAttendanceStartOn = terms.get(0).getAttendanceStartOn();
        Date termTotalAttendanceEndOn = terms.get(size - 1).getAttendanceEndOn();
        if (!DateUtils.isSameDay(attendanceStartOn, termTotalAttendanceStartOn)
                || !DateUtils.isSameDay(attendanceEndOn, termTotalAttendanceEndOn)) {
            ValidationUtils.reject(null, "账期考勤周期的起止时间必须与所有账期批次中全部考勤周期的总起止时间一致");
        }

        /**
         * term size为1 则全当作单批次做校验处理；
         */
        boolean planMonthCycle = size == 1;
        for (PayPeriodTermEntity term : terms) {
            term.setPlanMonthCycle(planMonthCycle);
            ValidationUtils.invokeValidator(payPeriodTermValidator, term);
        }

        // 账期批次中的时间连续
        if (size > 1) {
            for (int i = 0; i < size - 2; i++) {
                PayPeriodTermEntity termEntity1 = terms.get(i);
                PayPeriodTermEntity termEntity2 = terms.get(i + 1);
                if (isDateConsistent(termEntity1.getEndOn(), termEntity2.getStartOn())) {
                    ValidationUtils.reject(null, "薪资周期：前一个账期批次的结束时间与后一个账期批次的开始时间必须连续");
                }
                if (isDateConsistent(termEntity1.getAttendanceEndOn(), termEntity2.getAttendanceStartOn())) {
                    ValidationUtils.reject(null, "考勤周期：前一个账期批次的结束时间与后一个账期批次的开始时间必须连续");
                }
            }
        }
    }

    /**
     * 判断日期连续
     *
     * @param date1
     * @param date2
     * @return
     */
    private boolean isDateConsistent(Date date1, Date date2) {
        return DateUtils.addDays(DateUtils.dateFormatYMD(date1), 1)
                .compareTo(DateUtils.dateFormatYMD(date2)) == 0;
    }
}